package fnord.illuminati;

import java.io.Serializable;
import java.util.*;

import fnord.exception.BadCardException;
import fnord.exception.MapLoaderException;
import fnord.exception.MoneyException;
import fnord.illuminati.card.ActionCard;
import fnord.illuminati.card.Card;
import fnord.illuminati.card.GroupCard;
import fnord.network.server.Player;

public class Board implements Serializable {
	private static final long serialVersionUID = 7272745577908804956L;
	
	private Deck _deck;
	private Field _field;
	private Set<Player> _players;
	private Set<GroupCard> _destroyed;
	private Map<Integer, GroupCard> _visibleCards;
	private int _recentRoll;
	private Player _winner, _currentPlayer;
	private boolean _onlyMoneyTrans;
	private String _notification;
	private boolean _onlySpendMoney;
	
	private GroupCard _attackingCard, _defendingCard;
	
	public Deck getDeck() { return _deck; }
	public Field getField() { return _field; }
	public Set<Player> getPlayers() { return _players; }
	
	public Board(Set<Player> players) throws MapLoaderException {
		_deck = new Deck();
		_field = new Field();
		_players = players;
		_destroyed = new HashSet<GroupCard>();
		_visibleCards = new HashMap<Integer, GroupCard>();
		_winner = null;
		_notification = "Beginning of the game";
		setupInitial();
	}
	
	private void setupInitial() {
		while(_field.size() < 4) {
			Card c = _deck.drawCard();
			if(c instanceof GroupCard) {
				_field.add((GroupCard)c);
				_visibleCards.put(c.getId(), (GroupCard) c);
			}
			else {
				_deck.returnCardMiddle(c);
			}
			
		}
//		System.out.println(_players.size());
		
		/*for(Player p : _players) {
			try {
				p.getIlluminati().addMoney(p.getIlluminati().getIncome());
			} catch (MoneyException e) {
				System.err.println("this should never happen. the cards are wrong if so.");
			}
			_visibleCards.put(p.getIlluminati().getId(), p.getIlluminati());
			System.out.println("ILLUMINATI ID IS: "+p.getIlluminati().getId());
		}*/
	}
	
	public void draw(Player p) throws BadCardException {
		Card c = _deck.drawCard();
		if (c instanceof GroupCard) {
			_field.add((GroupCard)c);
			_visibleCards.put(c.getId(), (GroupCard) c);
		}
		else if (c instanceof ActionCard) {
			p.addActionCard((ActionCard)c);
		}
		else
			throw new BadCardException("Drawn card is neither a group nor action card.");
	}
	public void addToField(GroupCard to) {
		_field.add(to);
		
	}
	public void destroyCard(GroupCard to, Player player) {
		// TODO keep track of a kill count, and destroy the card, whatever that means...
		_field.remove(to);
		player.upKillCount();
		_destroyed.add(to);
	}
	
	public Map<Integer, GroupCard> getAllGroupCards() {
		return _visibleCards;
	}
	
	public void setCurrentPlayer(Player p) {
		_currentPlayer = p;
	}
	
	public Player getCurrentPlayer() { 
		return _currentPlayer;
	}
	
	public int getRecentRoll() { return _recentRoll; }
	public void setRecentRoll(int roll) { _recentRoll = roll; }
	public Player getWinner() { return _winner; }
	public void setWinner(Player winner) { _winner = winner; }
	public void setPlayers(Set<Player> pl) {
		_players = pl;
		for(Player p : _players) {
			try {
				p.getIlluminati().addMoney(p.getIlluminati().getIncome());
			} catch (MoneyException e) {
				System.err.println("this should never happen. the cards are wrong if so.");
			}
			_visibleCards.put(p.getIlluminati().getId(), p.getIlluminati());
//			System.out.println("ILLUMINATI ID IS: "+p.getIlluminati().getId());
		}
	}
	public void setOnlyMoneyTransfer(boolean b) {
		_onlyMoneyTrans = b;
	}
	public boolean getOnlyMoneyTransfer() { return _onlyMoneyTrans; }
	public void setOnlySpendMoney(boolean b) {
//		System.out.println("CHANGED TO " + b + "!");
		_onlySpendMoney = b;
	}
	public boolean getOnlySpendMoney() { return _onlySpendMoney; }
	public void setDefendingCard(GroupCard _defendingCard) {
	    this._defendingCard = _defendingCard;
    }
	public GroupCard getDefendingCard() {
	    return _defendingCard;
    }
	public void setAttackingCard(GroupCard _attackingCard) {
	    this._attackingCard = _attackingCard;
    }
	public GroupCard getAttackingCard() {
	    return _attackingCard;
    }
	public void setNotification(String _notification) {
		this._notification = _notification;
	}
	public String getNotification() {
		return _notification;
	}
}
